#Region "Using Directives"
Imports System
Imports System.Collections.Generic
Imports System.Text
#End Region

Namespace C4F.DevKit.Bluetooth
    Namespace ServiceAndDeviceDiscovery

        ''' <summary>
        ''' Helper class which imports a number of native APIs which help in 
        ''' communicating with the Bluetooth device 
        ''' and makes them available for use by other components.
        ''' </summary>
        Public NotInheritable Class BluetoothHelper

            Private WithEvents domain As AppDomain
            Private Sub New()
            End Sub

            ''' <summary>
            ''' Constructor for BluetoothHelper class.
            ''' </summary>
            ''' <exception cref="System.Exception">Thrown when winsock 
            ''' initialization fails.</exception>            
            Shared Sub New()
                ' Initialize WinSock.
                Dim wsadata As New WsaData()
                Dim result As Integer = BluetoothHelper.WSAStartup( _
                                            BluetoothHelper.MakeWord(2, 2), wsadata)
                If result <> 0 Then
                    Throw New Exception(BluetoothHelperMessages.errorMsgWinsockInit & _
                                        result.ToString())
                End If

                'Initialize a handler for Appdomain unload.

            End Sub

            ''' <summary>
            ''' Event Handler for AppDomain.DomainUnload event.
            ''' </summary>
            ''' <param name="sender">The sender of the event.</param>
            ''' <param name="e">EventArgs when the current Appdomain 
            ''' unloads.</param>  
            Private Shared Sub CurrentDomain_DomainUnload(ByVal sender As Object, _
                                                    ByVal e As EventArgs) _
                                                    Handles domain.DomainUnload
                'Cleans up the winsock layer.
                WSACleanup()
            End Sub

            ''' <summary>
            ''' Method for checking for Winsock errors.
            ''' </summary>            
            ''' <exception cref="WinsockException">Thrown when windows socket 
            ''' error occurs.</exception>   
            Public Shared Sub GetError()
                ' check for errors.
                Dim errorCode As Integer = BluetoothHelper.WSAGetLastError()
                Dim winsockError As New WinsockError()
                If errorCode <> 0 Then

                    With winsockError

                        Select Case errorCode
                            Case 10004
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10004
                                Exit Select
                            Case 10013
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10013
                                Exit Select
                            Case 10014
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10014
                                Exit Select
                            Case 10022
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10022
                                Exit Select
                            Case 10024
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10024
                                Exit Select
                            Case 10035
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10035
                                Exit Select
                            Case 10036
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10036
                                Exit Select
                            Case 10037
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10037
                                Exit Select
                            Case 10038
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10038
                                Exit Select
                            Case 10039

                                .ErrorMessage = BluetoothHelperMessages.errorMsg10039
                                Exit Select
                            Case 10040
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10040
                                Exit Select
                            Case 10041
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10041
                                Exit Select
                            Case 10042
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10042
                                Exit Select
                            Case 10043
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10043
                                Exit Select
                            Case 10044
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10044
                                Exit Select
                            Case 10045
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10045
                                Exit Select
                            Case 10046
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10046
                                Exit Select
                            Case 10047
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10047
                                Exit Select
                            Case 10048
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10048
                                Exit Select
                            Case 10049
                                winsockError.ErrorMessage = BluetoothHelperMessages.errorMsg10049
                                Exit Select
                            Case 10050
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10050
                                Exit Select
                            Case 10051
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10051
                                Exit Select
                            Case 10052
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10052
                                Exit Select
                            Case 10053
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10053
                                Exit Select
                            Case 10054
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10054
                                Exit Select
                            Case 10055
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10055
                                Exit Select
                            Case 10056
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10056
                                Exit Select
                            Case 10057
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10057
                                Exit Select
                            Case 10058
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10058
                                Exit Select
                            Case 10060
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10060
                                Exit Select
                            Case 10061
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10061
                                Exit Select
                            Case 10064
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10064
                                Exit Select
                            Case 10065
                                winsockError.ErrorMessage = BluetoothHelperMessages.errorMsg10065
                                Exit Select
                            Case 10067
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10067
                                Exit Select
                            Case 10091
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10091
                                Exit Select
                            Case 10094
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10094
                                Exit Select
                            Case 10093
                                Return
                            Case 10101
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10101
                                Exit Select
                            Case 10102
                                Return
                            Case 10103
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10103
                                Exit Select
                            Case 10104
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10104
                                Exit Select
                            Case 10105
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10105
                                Exit Select
                            Case 10106
                                winsockError.ErrorMessage = BluetoothHelperMessages.errorMsg10106
                                Exit Select
                            Case 10107
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10107
                                Exit Select
                            Case 10108
                                Return
                            Case 10109

                                .ErrorMessage = BluetoothHelperMessages.errorMsg10109
                                Exit Select
                            Case 10110
                                Return
                            Case 10111
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10111
                                Exit Select
                            Case 10112
                                .ErrorMessage = BluetoothHelperMessages.errorMsg10112
                                Exit Select
                            Case 11001
                                winsockError.ErrorMessage = BluetoothHelperMessages.errorMsg11001
                                Exit Select
                            Case 11002
                                .ErrorMessage = BluetoothHelperMessages.errorMsg11002
                                Exit Select
                            Case 11003
                                .ErrorMessage = BluetoothHelperMessages.errorMsg11003
                                Exit Select
                            Case 11004
                                .ErrorMessage = BluetoothHelperMessages.errorMsg11004
                                Exit Select
                            Case Else
                                Return
                        End Select

                        .ErrorCode = errorCode
                    End With

                    Throw New WinsockException(winsockError)
                End If

            End Sub

#Region "DLLImports"

            ''' <summary>
            ''' Imports the WSALookupServiceEnd native function.
            ''' </summary>
            ''' <param name="hLookup">Handle previously obtained by calling 
            ''' WSALookupServiceBegin.</param>
            ''' <returns>The return value is zero if the operation was 
            ''' successful. Otherwise, the value SOCKET_ERROR is returned, and
            ''' a specific error number can be retrieved by calling 
            ''' GetError.</returns>

            <System.Runtime.InteropServices.DllImport("ws2_32.dll", SetLastError:=True, _
                                                      EntryPoint:="WSALookupServiceEnd")> _
            Public Shared Function WSALookupServiceEnd(ByVal hLookup As IntPtr) As Integer
            End Function

            ''' <summary>
            ''' Imports the WSALookupServiceBegin native function.
            ''' </summary>
            ''' <param name="restriction">Pointer to the search 
            ''' criteria.</param>
            ''' <param name="controlFlags">Flag that controls the depth of
            ''' the search.</param>
            ''' <param name="lookup">Handle to be used when calling 
            ''' WSALookupServiceNext in order to start retrieving the results set.</param>
            ''' <returns>The return value is zero if the operation was 
            ''' successful. Otherwise, the value SOCKET_ERROR is returned, and
            ''' a specific error number can be retrieved by calling 
            ''' GetError.</returns>
            <System.Runtime.InteropServices.DllImport("ws2_32.dll", SetLastError:=True, _
                                        CharSet:=System.Runtime.InteropServices.CharSet.Auto, _
                                                      EntryPoint:="WSALookupServiceBegin")> _
            Public Shared Function WSALookupServiceBegin(ByVal restriction As QuerySet, _
                                                          ByVal controlFlags As UInteger, _
                                                          ByRef lookup As IntPtr) As Integer
            End Function

            ''' <summary>
            ''' Imports the WSALookupServiceNext native function.
            ''' </summary>
            ''' <param name="lookup">Handle returned from the previous
            ''' call to WSALookupServiceBegin.</param>
            ''' <param name="controlFlags">Flags to control the next operation. 
            ''' </param>
            ''' <param name="bufferLength">On input, the number of bytes contained 
            ''' in the buffer pointed to by results.</param>
            ''' <param name="results">Pointer to a block of memory, which 
            ''' will contain one result set in a queryset structure on return.
            ''' </param>
            ''' <returns>The return value is zero if the operation was 
            ''' successful. Otherwise, the value SOCKET_ERROR is returned, and
            ''' a specific error number can be retrieved by calling 
            ''' GetError.</returns>
            <System.Runtime.InteropServices.DllImport("ws2_32.dll", SetLastError:=True, _
                                                      CharSet:=System.Runtime.InteropServices.CharSet.Auto, _
                                                      EntryPoint:="WSALookupServiceNext")> _
            Public Shared Function WSALookupServiceNext(ByVal lookup As IntPtr, _
                                                         ByVal controlFlags As UInteger, _
                                                         ByRef bufferLength As Integer, _
                                                         ByVal results As IntPtr) As Integer
            End Function

            ''' <summary>
            ''' Imports the WSAStartup native function.
            ''' </summary>
            ''' <param name="wVersionRequested">Highest version of Windows Sockets 
            ''' support that the caller can use.</param>
            ''' <param name="wsaData">Pointer to the WSADATA data structure that is 
            ''' to receive details of the Windows Sockets implementation.</param>
            ''' <returns>The return value is zero if the operation was 
            ''' successful. Otherwise, the value SOCKET_ERROR is returned, and
            ''' a specific error number can be retrieved by calling 
            ''' GetError.</returns>
            <System.Runtime.InteropServices.DllImport("ws2_32.dll", SetLastError:=True, _
                                                      CharSet:=System.Runtime.InteropServices.CharSet.Auto, _
                                                      EntryPoint:="WSAStartup")> _
            Public Shared Function WSAStartup(ByVal wVersionRequested As Short, _
                                               ByRef wsaData As WsaData) As Integer
            End Function

            ''' <summary>
            ''' Imports the WSASetService native function.
            ''' </summary>
            ''' <param name="regInfo">Pointer to the service information for 
            ''' registration or deregistration.</param>
            ''' <param name="operation">Operation to be performed selected
            ''' from the WsaSetServiceOp enum.</param>
            ''' <param name="flags">Controls scope of operation.</param>
            ''' <returns>The return value is zero if the operation was 
            ''' successful. Otherwise, the value SOCKET_ERROR is returned, and
            ''' a specific error number can be retrieved by calling 
            ''' GetError.</returns>
            <System.Runtime.InteropServices.DllImport("ws2_32.dll", SetLastError:=True, _
                                                      EntryPoint:="WSASetService")> _
            Public Shared Function WSASetService(ByVal regInfo As QuerySet, _
                                                  ByVal operation As WsaSetServiceOp, _
                                                  ByVal flags As Integer) As Integer
            End Function

            ''' <summary>
            ''' Imports the WSAGetLastError native function.
            ''' </summary>
            ''' <returns>The return value indicates the error code for 
            ''' this thread's last Windows Sockets operation that failed.
            ''' </returns>
            <System.Runtime.InteropServices.DllImport("ws2_32.dll", SetLastError:=True, EntryPoint:="WSAGetLastError")> _
            Public Shared Function WSAGetLastError() As Integer
            End Function

            ''' <summary>
            ''' Imports the WSACleanup native function.
            ''' </summary>
            ''' <returns>The return value is zero if the operation was 
            ''' successful. Otherwise, the value SOCKET_ERROR is returned, and
            ''' a specific error number can be retrieved by calling 
            ''' GetError.</returns>
            <System.Runtime.InteropServices.DllImport("ws2_32.dll", SetLastError:=True, _
                                                      EntryPoint:="WSACleanup")> _
            Public Shared Function WSACleanup() As Integer
            End Function

            ''' <summary>
            ''' Imports the WSAAddressToString native function.
            ''' </summary>
            ''' <param name="address">Pointer to the sockaddr structure to 
            ''' translate into a string.</param>
            ''' <param name="addressLength">ength of the address in sockaddr, 
            ''' in bytes, which may vary in size with different protocols.</param>
            ''' <param name="protocolInfo">(Optional) The WSAPROTOCOL_INFO 
            ''' structure for a particular provider.</param>
            ''' <param name="addressString">Buffer that receives the 
            ''' human-readable address string.</param>
            ''' <param name="addressSize">Returns the length of the string 
            ''' actually copied into the buffer.</param>
            ''' <returns>The return value is zero if the operation was 
            ''' successful. Otherwise, the value SOCKET_ERROR is returned, and
            ''' a specific error number can be retrieved by calling 
            ''' GetError.</returns>
            <System.Runtime.InteropServices.DllImport("ws2_32.dll", SetLastError:=True, _
                                                      EntryPoint:="WSAAddressToString")> _
            Public Shared Function WSAAddressToString(ByVal address As IntPtr, _
                                                       ByVal addressLength As Short, _
                                                       ByVal protocolInfo As WsaProtocolInfo, _
                                                       ByVal addressString As IntPtr, _
                                                       ByRef addressSize As Integer) _
                                                       As Integer
            End Function


            ''' <summary>
            ''' Imports the BluetoothSdpGetElementData native function.
            ''' </summary>
            ''' <param name="sdpStream">A pointer to a valid SDP stream.</param>
            ''' <param name="sdpStreamLength">The length, in bytes, of pSdpStream
            ''' .</param>
            ''' <param name="data">A pointer to a buffer to be filled with the 
            ''' data of the SDP element found at the beginning of the pSdpStream
            ''' SDP stream.</param>
            ''' <returns>The return value is zero if the operation was 
            ''' successful. Otherwise, the value SOCKET_ERROR is returned, and
            ''' a specific error number can be retrieved by calling 
            ''' GetError.</returns>
            <System.Runtime.InteropServices.DllImport("Irprops.cpl", SetLastError:=True, _
                                                    CallingConvention:=System.Runtime. _
                                                    InteropServices.CallingConvention.Cdecl)> _
            Public Shared Function BluetoothSdpGetElementData(ByVal sdpStream As IntPtr, _
                                                        ByVal sdpStreamLength As UInteger, _
                                                        ByRef data As SdpElementData) _
                                                        As Integer
            End Function


            ''' <summary>
            ''' Imports the BluetoothSdpEnumAttributes native function.
            ''' </summary>
            ''' <param name="sdpStream">Pointer to a valid record stream that
            ''' is formatted as a single SDP record.</param>
            ''' <param name="streamSize">Size of the stream pointed to by 
            ''' sdpStream, in bytes.</param>
            ''' <param name="callbackHandler">Pointer to the callback routine.
            ''' </param>
            ''' <param name="param">Optional parameter to be passed to the 
            ''' callback routine.</param>
            ''' <returns>The return value is zero if the operation was 
            ''' successful. Otherwise, the value SOCKET_ERROR is returned, and
            ''' a specific error number can be retrieved by calling 
            ''' GetError.</returns>
            <System.Runtime.InteropServices.DllImport("Irprops.cpl", SetLastError:=True, _
                                                    CallingConvention:=System.Runtime. _
                                                  InteropServices.CallingConvention.StdCall)> _
            Public Shared Function BluetoothSdpEnumAttributes(ByVal sdpStream As IntPtr, _
                                                               ByVal streamSize As UInteger, _
                                                               ByVal callbackHandler As  _
                                                               CallbackEventHandler, _
                                                               ByVal param As IntPtr) _
                                                               As Boolean
            End Function

#End Region

#Region "Constants"

            ''' <summary>
            ''' Represents the socket address length.
            ''' </summary>
            Public Const SOCKET_ADDRESS_LENGTH As Integer = 30

            ''' <summary>
            ''' Represents the address offset.
            ''' </summary>
            Public Const ADDRESS_OFFSET As Integer = 2

            ''' <summary>
            ''' Represents Guid offset.
            ''' </summary>
            Public Const GUID_OFFSET As Integer = 10

            ''' <summary>
            ''' Represents the channel offset.
            ''' </summary>
            Public Const CHANNEL_OFFSET As Integer = 26

            ''' <summary>
            ''' Represents the default channel.
            ''' </summary>
            Public Const ANY_CHANNEL As Integer = -1

            ''' <summary>
            ''' Represents the Bluetooth namespace.
            ''' </summary>
            Public Const NS_BTH As Integer = 16

            ''' <summary>
            ''' Represents the version of SDP.
            ''' </summary>                                 
            Public Const BTH_SDP_VERSION As Integer = 1

            ''' <summary>
            ''' Represents the maximum number of characters for describing the 
            ''' Windows Sockets implementation.
            ''' </summary>
            Public Const WSADESCRIPTION_LEN As Integer = 256

            ''' <summary>
            ''' Represents the maximum number of characters for describing 
            ''' the relevant status or configuration information.
            ''' </summary>
            Public Const WSASYS_STATUS_LEN As Integer = 128

            ''' <summary>
            ''' Represents the maximum number of characters for describing a 
            ''' protocol.
            ''' </summary>
            Public Const WSAPROTOCOL_LEN As Integer = 255

            ''' <summary>
            ''' Represents the Length of protocol chain.
            ''' </summary>
            Public Const MAX_PROTOCOL_CHAIN As Integer = 7

            ''' <summary>
            ''' Represents the LUP_DEEP flag.
            ''' </summary>
            Public Const LUP_DEEP As Integer = 1

            ''' <summary>
            ''' Represents the LUP_CONTAINERS flag.
            ''' </summary>
            Public Const LUP_CONTAINERS As Integer = 2

            ''' <summary>
            ''' Represents the LUP_RETURN_NAME flag.
            ''' </summary>
            Public Const LUP_RETURN_NAME As Integer = 16

            ''' <summary>
            ''' Represents the LUP_RETURN_TYPE flag.
            ''' </summary>
            Public Const LUP_RETURN_TYPE As Integer = 32

            ''' <summary>
            ''' Represents the LUP_RETURN_COMMENT flag.
            ''' </summary>
            Public Const LUP_RETURN_COMMENT As Integer = 128

            ''' <summary>
            ''' Represents the LUP_RETURN_ADDR flag.
            ''' </summary>
            Public Const LUP_RETURN_ADDR As Integer = 256

            ''' <summary>
            ''' Represents the LUP_RETURN_BLOB flag.
            ''' </summary>
            Public Const LUP_RETURN_BLOB As Integer = 512

            ''' <summary>
            ''' Represents the LUP_RETURN_ALL flag.
            ''' </summary>
            Public Const LUP_RETURN_ALL As Integer = 4080

            ''' <summary>
            ''' Represents the LUP_RES_SERVICE flag.
            ''' </summary>
            Public Const LUP_RES_SERVICE As Integer = 32768

            ''' <summary>
            ''' Represents the LUP_FLUSHCACHE flag.
            ''' </summary>
            Public Const LUP_FLUSHCACHE As Integer = 4096


            ''' <summary>
            ''' Represents the Serial Port Profile Guid.
            ''' </summary>
            Public Shared SERIAL_PORT_PROFILE As New Guid("00001101-0000-1000-8000-00805F9B34FB")

            ''' <summary>
            ''' Represents the Object Push Profile Guid.
            ''' </summary>
            Public Shared OBJECT_PUSH_PROFILE As New Guid("00001105-0000-1000-8000-00805F9B34FB")

            ''' <summary>
            ''' Represents the File Transfer Profile Guid.
            ''' </summary>
            Public Shared FILE_TRANSFER_PROFILE As New Guid("00001106-0000-1000-8000-00805F9B34FB")

            ''' <summary>
            ''' Represents the Public Browse Root Guid.
            ''' </summary>
            Public Shared PUBLIC_BROWSE_UUID As New Guid("00001002-0000-1000-8000-00805F9B34FB")

#End Region

#Region "Helper Functions"

            ''' <summary>
            ''' Gets the highest version of Windows Sockets support that 
            ''' the caller can use.
            ''' </summary>
            ''' <param name="low">Specifies the major version number.</param>
            ''' <param name="high">Specifies the minor version (revision) number.
            ''' </param>
            ''' <returns>Highest version of windows socket support that the caller
            ''' can use.</returns>
            Public Shared Function MakeWord(ByVal low As Byte, ByVal high As Byte) As Short
                Return CShort(((low) Or CShort((high)) << 8))
            End Function

            ''' <summary>
            ''' Delegate used by the BluetoothSdpEnumAttributes function.
            ''' </summary>
            ''' <param name="attribId">Identifies the current attribute in the
            ''' service record.</param>
            ''' <param name="valueStream">Represents the value associated with 
            ''' the attribute.</param>
            ''' <param name="streamSize">size in bytes of valueStream.</param>
            ''' <param name="param">Optional.The context passed in from a previous call 
            ''' to the BluetoothSdpEnumAttributes function.</param>
            ''' <returns>Returns TRUE when the enumeration continues to the next 
            ''' attribute identifier found in the stream. Return FALSE
            ''' when enumeration of the record attribute identifiers should 
            ''' immediately stop.</returns>
            <System.Runtime.InteropServices.UnmanagedFunctionPointer(System.Runtime. _
                                                InteropServices.CallingConvention.StdCall, _
                                                                     SetLastError:=True)> _
            Public Delegate Function CallbackEventHandler(ByVal attribId As UInteger, _
                                                           ByVal valueStream As IntPtr, _
                                                           ByVal streamSize As UInteger, _
                                                            ByVal param As IntPtr) As Boolean
#End Region
        End Class

    End Namespace

End Namespace
